package xfuzzy.alg_genetico.indeterminado.xfghlOld.model;

//import java.awt.image.BufferStrategy;
//import java.nio.Buffer;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Random;

public class XfghlGeneration {

	/**
	 * N�mero aleatorio
	 */
	private Random random;

	/**
	 * Poblaci�n
	 */
	private ArrayList<XfghlChromosome> chromosomes;

	/**
	 * Configuraci�n de la herramienta
	 */
	private XfghlConfig config = null;

	/**
	 * Vector de pesos acumulados para s�lo calcularlo una vez
	 */
	private int[] pesosAcu = null;

	/**
	 * Const
	 * 
	 * @param numChrom
	 * @param isRandom
	 *            Indica si la poblaci�n se inicializa aleatoriamente
	 */
	public XfghlGeneration(XfghlConfig config, boolean isRandom) {

		// Incializamos los atributos de la clase
		// int numChrom=config.getNumChrom();

		this.config = config;
		this.random = XfghlSinglRandom.getRandom();
		this.chromosomes = new ArrayList<XfghlChromosome>();

		// Verificamos si tenemos que crear la poblaci�n desde cero
		if (isRandom) {
			initializeRandom();
		}
	}

	/**
	 * 
	 * @return Devuelve un cromosoma aleatoriamente con la misma probabilidad
	 */
	public XfghlChromosome getRandomChromosome() {
		// Vemos si tenemos que calcular el vector de pesos acumulados
		if (this.pesosAcu == null)
			calculatePesosAcu();

		// El valor m�ximo es el que tiene la ultima posici�n del vector
		int valor = this.random.nextInt(this.pesosAcu[this.pesosAcu.length - 1]);

		// Buscamos el indice del cromosoma a devolver
		boolean encontrado = false;
		int pos = 0;

		// Buscamos d�nde tenemos que a�adirlo en la lista
		while (!encontrado && pos < this.pesosAcu.length) {

			// Vemos en que posici�n lo tenemos que poner
			if (valor < this.pesosAcu[pos]) {
				encontrado = true;
			} else {
				pos++;
			}
		}
		// En pos tenemos el �ndice a devolver
		return this.chromosomes.get(pos);
	}

	/**
	 * Calcula el vector de pesos acumulados
	 */
	private void calculatePesosAcu() {

		int acu = 0;
		this.pesosAcu = new int[this.chromosomes.size()];

		// Calculamos el vector acumulado
		for (int i = 0; i < this.pesosAcu.length; i++) {
			this.pesosAcu[i] = (int) (1 / this.chromosomes.get(i).getFinalError()) + acu;
			acu = this.pesosAcu[i];
		}
	}

	/**
	 * Ordena la poblaci�n de menor a mayor error final error
	 */
	public void orderPoblation() {
		// Nos creamos una nueva poblaci�n
		ArrayList<XfghlChromosome> newPobl = new ArrayList<XfghlChromosome>();
		Iterator<XfghlChromosome> it = this.chromosomes.iterator();

		// Insertamos de nuevo todos los cromosomas ordenadamente
		while (it.hasNext()) {
			// Nuevo
			XfghlChromosome insertChrom = it.next();

			boolean encontrado = false;
			int pos = 0;

			// Buscamos d�nde tenemos que a�adirlo en la lista
			while (!encontrado && pos < newPobl.size()) {

				// Vemos en que posici�n lo tenemos que poner
				if (insertChrom.getFinalError() < newPobl.get(pos).getFinalError() || newPobl.size() == 0) {
					encontrado = true;
				} else {
					pos++;
				}
			}
			// Insertamos el elemento en la posicion
			newPobl.add(pos, insertChrom);
		}
		// Actualizamos la poblaci�n
		this.chromosomes = newPobl;
	}

	/**
	 * Getter and Setter
	 * 
	 */
	public ArrayList<XfghlChromosome> getChromosomes() {
		return chromosomes;
	}

	/**
	 * Obtiene un chromosoma de la poblaci�n del indice
	 * 
	 * @param ind
	 *            indice de la poblaci�n
	 * @return cromosoma a devolver
	 */
	public XfghlChromosome getChromosome(int ind) {
		return this.chromosomes.get(ind);
	}

	public void setChromosomes(ArrayList<XfghlChromosome> chromosomes) {
		this.chromosomes = chromosomes;
		this.pesosAcu = null;
	}

	/**
	 * 
	 * @return N�mero de individuos de la poblaci�n
	 */
	@SuppressWarnings("unused")
	private int getNumChrom() {
		return this.chromosomes.size();
	}

	/**
	 * A�ade un individuo a la poblaci�n
	 * 
	 * @param chrom
	 *            Individuo
	 */
	public void addChromosome(XfghlChromosome chrom) {
		this.chromosomes.add(chrom);
	}

	/**
	 * Generamos la poblaci�n aleatoriamente
	 */
	private void initializeRandom() {
		// N�mero de cromosomas
		int numChrom = config.getNumChrom();

		for (int i = 0; i < numChrom; i++) {
			XfghlChromosome c = new XfghlChromosome(this.config, true);
			c.setId(i);
			this.chromosomes.add(c);
		}
	}

	/**
	 * M�todo que devuelve los dos mejores cromosomas de la generaci�n sin ser
	 * repetidos
	 * 
	 * @return
	 */
	public XfghlChromosome[] twoBest() {
		XfghlChromosome[] best = new XfghlChromosome[2];

		double best1 = 1, best2 = 1;

		// Buscamos el primer mejor
		for (XfghlChromosome c : this.chromosomes) {
			if (best1 > c.getFinalError()) {
				best1 = c.getFinalError();
				best[0] = c;
			}
		}

		// Buscamos el segundo mejor
		for (XfghlChromosome c : this.chromosomes) {
			// Comprobamos que no
			if (best2 > c.getFinalError() && !best[0].toString().equals(c.toString())) {
				best2 = c.getFinalError();
				best[1] = c;
			}
		}

		return best;
	}

	/**
	 * M�todo que nos dice si la generac�on contiene al cromosoma c
	 * 
	 * @param c
	 * @return
	 */
	public boolean containChromosome(XfghlChromosome c) {
		// Buscamos el primer mejor
		for (XfghlChromosome c1 : this.chromosomes) {
			if (c1.toString().equals(c.toString())) {
				return true;
			}
		}
		return false;
	}

	/**
	 * 
	 */
	@SuppressWarnings("unused")
	public String toString() {

		StringBuffer sb = new StringBuffer();
		int i = 0;
		sb.append("Generacion:\n");
		for (XfghlChromosome c : this.chromosomes) {
			sb.append("\n\t" + c.toString() + " " + c.getFinalError() + " ");
			i++;
		}
		sb.append("\nFIN Generacion.");

		return sb.toString();
	}

}
